<template>
  <el-popover placement="bottom" :width="400" trigger="click" popper-class="upload-popover">
    <template #reference>
      <a-button type="primary">
        <template #icon><UploadOutlined /></template>
        上传列表
      </a-button>
    </template>

    <div class="upload-list">
      <div class="upload-list-header">
        <span>上传任务</span>
        <span class="tips">（仅展示最新10条上传任务）</span>
      </div>
      <div class="upload-list-content">
        <template v-if="uploadFileList.length">
          <div v-for="item in uploadFileList.slice(0, 10)" :key="item.uid" class="upload-item">
            <div class="file-name" :title="item.fileName">
              {{ item.fileName }}
            </div>
            <a-progress
              v-if="item.status === 'uploading'"
              :percent="item.uploadProgress"
              size="small"
            />
            <div class="upload-status">
              <span :class="getStatusClass(item.status)">
                {{ getStatusText(item.status) }}
              </span>
              <template v-if="item.status === 'fail'">
                <a-button type="link" @click="retryUpload(item)"> 重试 </a-button>
                <a-button type="link" danger @click="removeUploadItem(item)"> 删除 </a-button>
              </template>
            </div>
          </div>
        </template>
        <div v-else class="empty-tip">暂无上传任务</div>
      </div>
    </div>
  </el-popover>
</template>

<script setup lang="ts">
  import { ref } from 'vue'
  import { message } from 'ant-design-vue'
  import { UploadOutlined } from '@ant-design/icons-vue'
  import SparkMD5 from 'spark-md5'
  import { uploadFileUsingPost } from '@/api/wenjianmokuai'

  const uploadFileList = ref([])

  // 计算文件的MD5
  const computeFileMD5 = file => {
    return new Promise((resolve, reject) => {
      const blobSlice =
        File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
      const chunkSize = 2097152 // 每次读取 2MB
      const chunks = Math.ceil(file.size / chunkSize)
      let currentChunk = 0
      const spark = new SparkMD5.ArrayBuffer()
      const fileReader = new FileReader()

      fileReader.onload = e => {
        spark.append(e.target.result)
        currentChunk++

        if (currentChunk < chunks) {
          loadNext()
        } else {
          const md5 = spark.end()
          resolve(md5)
        }
      }

      fileReader.onerror = e => {
        reject(e)
      }

      const loadNext = () => {
        const start = currentChunk * chunkSize
        const end = start + chunkSize >= file.size ? file.size : start + chunkSize
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
      }

      loadNext()
    })
  }

  // 添加文件到上传列表
  const addFile = async (file, filePid = '0') => {
    if (!file || !file.uid) {
      console.error('文件对象无效或缺少uid')
      return
    }

    // 检查是否已存在相同文件
    const existingFile = uploadFileList.value.find(
      item => item.fileName === file.name && item.status !== 'fail'
    )

    if (existingFile) {
      message.warning(`文件 ${file.name} 已在上传列表中`)
      return
    }

    // 计算文件MD5
    const fileMd5 = await computeFileMD5(file)

    const fileItem = {
      uid: file.uid,
      file: file,
      fileName: file.name,
      fileSize: file.size,
      fileType: file.type,
      filePid: filePid,
      fileMd5: fileMd5,
      status: 'init',
      uploadProgress: 0,
      errorMsg: null,
      chunkIndex: 0,
      chunks: Math.ceil(file.size / (2 * 1024 * 1024)), // 2MB per chunk
      fileId: null,
    }

    uploadFileList.value.unshift(fileItem)
    startUpload(fileItem)
  }

  // 开始上传文件
  const startUpload = async fileItem => {
    try {
      if (!fileItem || !fileItem.file) {
        console.error('文件对象无效')
        return
      }

      const chunkSize = 2 * 1024 * 1024 // 2MB per chunk
      const totalChunks = fileItem.chunks
      const file = fileItem.file

      fileItem.status = 'uploading'

      for (let chunkIndex = fileItem.chunkIndex; chunkIndex < totalChunks; chunkIndex++) {
        const start = chunkIndex * chunkSize
        const end = Math.min(start + chunkSize, file.size)
        const chunk = file.slice(start, end)

        const formData = new FormData()
        formData.append('file', chunk)
        formData.append('fileName', fileItem.fileName)
        formData.append('fileSize', fileItem.fileSize)
        formData.append('fileMd5', fileItem.fileMd5)
        formData.append('chunkIndex', chunkIndex)
        formData.append('chunks', totalChunks)
        formData.append('fileId', fileItem.fileId || '')
        formData.append('filePid', fileItem.filePid || '0')

        const result = await uploadFileUsingPost(formData)

        if (result.data?.code === 200) {
          fileItem.fileId = result.data.data.fileId
          fileItem.chunkIndex = chunkIndex + 1
          fileItem.uploadProgress = Math.round(((chunkIndex + 1) * 100) / totalChunks)

          if (chunkIndex === totalChunks - 1) {
            fileItem.status = 'upload_finish'
            fileItem.uploadProgress = 100
            message.success('上传成功')
            break
          }
        } else {
          fileItem.status = 'fail'
          fileItem.errorMsg = result.data?.message || '上传失败'
          message.warning(result.data?.message || '上传失败')
          break
        }
      }
    } catch (error) {
      console.error('文件上传失败:', error)
      if (fileItem) {
        fileItem.status = 'fail'
        fileItem.errorMsg = '上传失败: ' + (error.message || '未知错误')
      }
      message.error('上传失败，请稍后重试')
    }
  }

  // 重试上传
  const retryUpload = fileItem => {
    if (!fileItem || !fileItem.file) {
      message.error('文件已不存在，无法重试')
      return
    }
    startUpload(fileItem)
  }

  // 移除上传项
  const removeUploadItem = fileItem => {
    if (!fileItem || !fileItem.uid) {
      console.error('无效的文件项')
      return
    }

    const index = uploadFileList.value.findIndex(item => item.uid === fileItem.uid)
    if (index > -1) {
      uploadFileList.value.splice(index, 1)
      message.success('已移除文件')
    }
  }

  // 获取状态样式类
  const getStatusClass = status => {
    const classes = {
      init: 'status-init',
      uploading: 'status-uploading',
      upload_finish: 'status-success',
      upload_seconds: 'status-success',
      fail: 'status-error',
      emptyfile: 'status-error',
    }
    return classes[status] || ''
  }

  // 获取状态文本
  const getStatusText = status => {
    const texts = {
      init: '准备上传',
      uploading: '上传中',
      upload_finish: '上传完成',
      upload_seconds: '秒传完成',
      fail: '上传失败',
      emptyfile: '文件为空',
    }
    return texts[status] || status
  }

  defineExpose({
    addFile,
  })
</script>

<style scoped lang="less">
  .upload-popover {
    padding: 0;
    border-radius: 8px;
  }

  .upload-list {
    .upload-list-header {
      padding: 12px 16px;
      border-bottom: 1px solid #eee;
      font-size: 14px;
      font-weight: 500;

      .tips {
        font-size: 12px;
        color: #999;
        margin-left: 8px;
        font-weight: normal;
      }
    }

    .upload-list-content {
      max-height: 400px;
      overflow-y: auto;

      .upload-item {
        padding: 12px 16px;
        border-bottom: 1px solid #eee;

        &:last-child {
          border-bottom: none;
        }

        .file-name {
          font-size: 14px;
          margin-bottom: 8px;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }

        .upload-status {
          display: flex;
          align-items: center;
          margin-top: 8px;
          font-size: 13px;

          .status-init {
            color: #909399;
          }

          .status-uploading {
            color: #409eff;
          }

          .status-success {
            color: #67c23a;
          }

          .status-error {
            color: #f56c6c;
          }

          .el-button {
            margin-left: 12px;
            padding: 0;
          }
        }
      }

      .empty-tip {
        padding: 32px;
        text-align: center;
        color: #909399;
        font-size: 14px;
      }
    }
  }
</style>
